package dkbta.ontology.loading;

import static dkbta.ontology.elements.ElementType.STAT;
import static dkbta.ontology.elements.ElementType.SUBJECTSTAT;
import static dkbta.ontology.loading.OntologyParser.getXmlElement;
import static dkbta.ontology.loading.OntologyParser.parseDurationCondition;
import static dkbta.ontology.loading.OntologyParser.parseDurationValues;
import static dkbta.ontology.loading.OntologyParser.parseValueConsdition;
import static dkbta.util.Utils.enumForName;

import java.util.EnumSet;
import java.util.Set;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import dkbta.ontology.Ontology;
import dkbta.ontology.elements.ElementType;
import dkbta.ontology.elements.pattern.conditions.DurationCondition;
import dkbta.ontology.elements.repeatingpattern.RepeatingPatternDef;
import dkbta.ontology.loading.OntologyParser.ElementParser;
import dkbta.ontology.values.DurationValues;
import dkbta.ontology.values.ValueCondition;
import dkbta.util.Utils;

final class RepeatingPatternParser implements ElementParser{
	private final Set<ElementType> _invalidPatternElementTypes = EnumSet.of(STAT,
		SUBJECTSTAT);
	
	private final Ontology _ontology;


	public RepeatingPatternParser(Ontology ontology){
		_ontology = ontology;
	}

	@Override
	public ElementType getElementType(){
		return ElementType.REPEATINGPATTERN;
	}

	public void parseElement(Element repPattern, String name, String componentType)
			throws OntologyException{
		Element peElement = getXmlElement(repPattern, "Element");
		if (peElement == null){
			throw new OntologyException("There is no pattern element");
		}

		// Obtaining the ontology element node
		Element ontElement = getOntologyElement(peElement);
		String patternElementTypeStr = ontElement.getTagName();

		// Parsing the ontology element the pattern is based on
		ElementType et = enumForName(ElementType.class, patternElementTypeStr);
		if (_invalidPatternElementTypes.contains(et)){
			throw new OntologyException("Invalid pattern element type: " + et);
		}

		String ontElementName = ontElement.getAttribute("name");
		if (Utils.isEmpty(ontElementName)){
			throw new OntologyException("Invalid ontology element name: "
					+ ontElementName);
		}

		// Parsing the local conditions
		ValueCondition vc = parseValueConsdition(ontElement, patternElementTypeStr,
			_invalidPatternElementTypes, true);
		DurationCondition dc = parseDurationCondition(ontElement);

		if (vc == null && dc == null){
			throw new OntologyException("No conditions defined on the element");
		}

		// Parsing the cardinality and gap interval
		Element constraints = getXmlElement(repPattern, "Constraints");
		int cardinality;
		String cardinalityStr = constraints.getAttribute("cardinality");
		if (Utils.isEmpty(cardinalityStr) || !Utils.isDigitsOnly(cardinalityStr)
				|| (cardinality = Integer.valueOf(cardinalityStr)) < 1){
			throw new OntologyException("Invalid/missing cardinality: " + cardinalityStr);
		}
		DurationValues validGapDuration;
		try{
			validGapDuration = parseDurationValues(constraints, "minGap", "maxGap");
		}catch(OntologyException e){
			throw new OntologyException("Missing/invalid minGap[E]/maxGap[E] attributes",
					e);
		}

		RepeatingPatternDef rpd = new RepeatingPatternDef(name, componentType,
				ontElementName, et, vc, dc, cardinality, validGapDuration);
		_ontology.addRepeatingPattern(rpd);
	}

	private Element getOntologyElement(Element peElement) throws OntologyException{
		NodeList childNodes = peElement.getChildNodes();

		int elementNodeCount = 0;
		Element ontElement = null;
		for (int i = 0; i < childNodes.getLength(); ++i){
			Node node = childNodes.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE){
				elementNodeCount++;
				ontElement = (Element)node;
			}
		}

		if (elementNodeCount != 1){
			throw new OntologyException("Invalid number of ontology elements: "
					+ elementNodeCount);
		}
		return ontElement;
	}

}